﻿using ServerCommon.Log;
using ServerCommon.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ServerCommon.Net
{
    public class NetSessionConfig
    {
        //socket发送数据的缓冲大小
        public int SocketSendBufferSize;

        //发送缓存中一条数据的消息，一般情况下设置的大小应该与 SocketSendBufferSize 相同
        public int CacheSendBufferSize;

        //socket接收数据的缓冲大小
        public int SocketRecvBufferSize;

        //接收缓存中一条数据的消息，一般情况下设置的大小应该与 SocketRecvBufferSize 相同
        public int CacheRecvBufferSize;

        public NetSessionConfig()
        {
            SocketSendBufferSize = 8 * 1024;
            CacheSendBufferSize = 8 * 1024;
            SocketRecvBufferSize = 8 * 1024;
            CacheRecvBufferSize = 8 * 1024;
        }

        public static NetSessionConfig GetConfigByNodeType(EnumNodeServiceType nodeType)
        {
            var config = new NetSessionConfig();
            config.SocketRecvBufferSize = 128 * 1024;
            config.SocketSendBufferSize = 128 * 1024;
            return config;
        }
    }

    public class NetSession
    {
        //
        private static LogHelper _log = LogHelper.GetLogger(typeof(NetSession));

        //检查当前socket是否处于发送状态
        private int _isInSending;

        // 待发送的数据
        private BufferProtocol _pendingSendDataEx;
        private ObjectPool<BufferMemory> _sendMemoryPool;

        // _socket对应的客户端地址
        public EndPoint RemoteEndPoint
        {
            get { return _remoteEndPoint; }
        }
        private IPEndPoint _remoteEndPoint;

        // 底层用的实际socket
        public Socket WorkSocket
        {
            get { return _socket; }
        }
        private Socket _socket;

        // 唯一标识，区分用户
        public Guid HashCode { get; set; }

        public object SocketSyncLock = new object();

        //远端节点的服务类型
        public EnumNodeServiceType _serviceType;

        public long _localNodeId;
        public long _remoteNodeId;

        public NetSession(Socket socket, NetSessionConfig socketConfig, Guid hashCode, EnumNodeServiceType serviceType)
        {
            _socket = socket;
            _socket.NoDelay = true;
            _socket.SendBufferSize = socketConfig.SocketSendBufferSize;
            _socket.ReceiveBufferSize = socketConfig.SocketRecvBufferSize;

            _sendMemoryPool = new ObjectPool<BufferMemory>(10, 5);

            _pendingSendDataEx = new BufferProtocol(socketConfig.CacheSendBufferSize, _sendMemoryPool);

            _remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint;
            _isInSending = 0;

            _serviceType = serviceType;

            HashCode = hashCode;
            _localNodeId = 0;
            _remoteNodeId = 0;
        }

        /// 关闭连接
        public void Close()
        {
            try
            {
                _log.InfoFormat("Close socket RemoteEndPoint:{0}", RemoteEndPoint?.ToString());
                if (_socket != null)
                {
                    if (_socket.Connected)
                    {
                        _socket.Shutdown(SocketShutdown.Both);
                    }
                    _socket.Close();
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("NetSession close error: {0} {1}", ex.Message, HashCode);
            }
        }

        //逻辑层要发送的数据写到这里缓存
        //<param name="data">要发送的数据</param>
        public void Write(byte[] data)
        {
            _pendingSendDataEx.WriteLock(data.Length, data);
        }

        //socket读取缓存中的数据，准备发送
        //<param name="buff">socketAsyncEventArgs的Buffer地址</param>
        //<param name="offset">数据读取的偏移量</param>
        //<param name="len">想要读取的数据长度</param>
        //如果读到的数据长度为0，则ResetSendFlag
        public int ReadAndResetSendFlag(byte[] buff, int offset, int len)
        {
            return _pendingSendDataEx.Read(buff, offset, len);
        }

        //计算当前发送缓存中的数据长度
        //<returns></returns>
        public int PendingSendDataLen()
        {
            return _pendingSendDataEx.DataLen;
        }

        //location1与comparand相比，如果相等就将location1替换为value的值
        //如果返回true，说明没有消息正在发送，需要手动触发postsend
        //如果返回false，说明有消息正在发送，不用再主动postsend
        public bool TrySetSendFlag()
        {
            return Interlocked.CompareExchange(ref _isInSending, 1, 0) == 0;
        }

        //重置发送标记
        public void ResetSendFlag()
        {
            Interlocked.Exchange(ref _isInSending, 0);
        }

        public int GetSendingFlag()
        {
            return _isInSending;
        }

        //解析IP
        public string GetIP()
        {
            string ip = "";
            if (RemoteEndPoint != null)
            {
                var remoteStr = RemoteEndPoint.ToString();
                var strs = remoteStr.Split(':');
                ip = strs[0];
            }
            return ip;
        }
    }
}
